www.gusucode.com > VC++ 图片浏览器的设计与实现+设计文档源码程序 > VC++ 图片浏览器的设计与实现+设计文档源码程序/code/PictView/ImagePcx.cpp

    //Download by http://www.NewXing.com
//*************************************************************************************************
//ImagePcx.cpp:包含本程序需要PCX图像的读入代码
//*************************************************************************************************
#include "stdafx.h"
#include "ClassImage.h"

static BYTE * RLE_PCX_Decode8(BYTE * InBuffer,int nInSize,BYTE * OutBuffer)
{
	register BYTE Data,Num;
	while(nInSize > 0)
	{
		Data = *InBuffer++;
		if((Data & 0xC0) == 0xC0)
		{
			Num = Data & 0x3F;
			memset(OutBuffer,*InBuffer++,Num);
			OutBuffer += Num;
			nInSize -= Num;
		}
		else
		{
			*OutBuffer++ = Data;
			nInSize--;
		}
	}
	return InBuffer;
}

static int RLE_PCX_Decode24(BYTE * InBuffer,int nInSize,BYTE * OutBuffer)
{
	register BYTE Data,Num;
	register int nWrite = 0;
	while(nInSize-- > 0)
	{
		Data = *InBuffer++;
		if((Data & 0xC0) == 0xC0)
		{
			Num = Data & 0x3F;
			memset(OutBuffer,*InBuffer++,Num);
			OutBuffer += Num;
			nWrite += Num;
			nInSize--;
		}
		else
		{
			*OutBuffer++ = Data;
			nWrite++;
		}
	}
	return nWrite;
}

#pragma pack(push)
#pragma pack(1)

typedef struct tagPCXHEAD
{
	BYTE manufacturer;
		//0x0A
	BYTE version;
		//0,2,3,4,5
	BYTE encoding;
		//1 RLE
	BYTE bit_per_pixel;
		//1,4,8
	WORD xmin;
	WORD ymin;
	WORD xmax;
	WORD ymax;
	WORD Xresolution;
	WORD Yresolution;
	BYTE palette[48];
		//1或4Bits图象调色板
	BYTE reserved;
		//0
	BYTE color_planes;
		//色彩平面数目(1,3,4)
	WORD byte_per_line;
		//每行图象的字节宽度
	WORD palette_type;
		//1
	WORD screen_width;
	WORD screen_height;
	BYTE filter[54];
		//0
}PCXHEAD, *PPCXHEAD;

typedef struct tagPCXPALETTE
{
  BYTE rgbRed;
  BYTE rgbGreen;
  BYTE rgbBlue;
} PCXPALETTE;
#pragma pack(pop)

/****
****** Write a single line of a PCX file. *******
****/
BOOL WritePCXLine(int bytes, BYTE *p, FILE *fp)
{
	unsigned int i=0, j=0, t=0;

	do
	{
		i = 0;
		while ((p[t+i]==p[t+i+1]) && ((t+i)<(WORD)bytes) && (i<63))
			++i;
		if (i > 0) /* there are i equal pixels from current position */
		{
			fputc(i|0xc0, fp);          /* write duplicated number */
			fputc(p[t], fp);           /* write pixel value */
			t += i;						/* bytes have been processed */
			j += 2;						/* bytes have been written to file */
		}
		else	/* no duplicated pixel */
		{
			if (((p[t]) & 0xc0) == 0xc0) /* pixel value > 192 ? */
			{
				fputc(0xc1, fp);        /* write identify sign 0xc1 */
				++j;
			}
			fputc(p[t++], fp);
			++j;
		}
	} while (t < (WORD)bytes);

	return (ferror(fp) ? FALSE : TRUE);
}

//******************* 读取PCX ***********************
BOOL LanImage::ReadPcx(LPBYTE pFileBuffer,UINT nFileSize,int ndegree)
{
	PCXHEAD * ph = (PCXHEAD *)pFileBuffer;
	if(ph->manufacturer != 0x0A)
		return FALSE;

	int nWidth = ph->xmax - ph->xmin + 1;
	int nHeight = ph->ymax - ph->ymin + 1;
	int nBitCount = ph->bit_per_pixel * ph->color_planes;

	Create(nWidth,nHeight,nBitCount,ndegree);

	if(nBitCount <= 8)
	{
		BYTE * pImage = pFileBuffer + sizeof(PCXHEAD);
		//非颠倒
		if(UC_SWAP_HEIGHT(0))
		{
			BYTE * pOut = GetLine(0);
			for(int y=0; y<nHeight; ++y)
			{
				pImage = RLE_PCX_Decode8(pImage,ph->byte_per_line,pOut);
				pOut += m_nPitch;
			}
		}
		else
		{//图象颠倒
			BYTE * pOut = GetLine(m_nHeight - 1);
			for(int y=0; y<nHeight; ++y)
			{
				pImage = RLE_PCX_Decode8(pImage,ph->byte_per_line,pOut);
				pOut -= m_nPitch;
			}
		}
	}
	else // 24,32
	{
		BYTE * const pImage = new BYTE[ph->color_planes * ph->byte_per_line * nHeight + 1024];
		int nWrite = RLE_PCX_Decode24(pFileBuffer + sizeof(PCXHEAD),
										nFileSize - sizeof(PCXHEAD),
										pImage);
		BYTE * pCur = pImage;
		
		if(UC_SWAP_HEIGHT(0))
		{//非颠倒
			for(int y=0; y<nHeight; ++y)
			{
				BYTE * pOut = GetLine(y);
				BYTE * pRed = pCur;
				BYTE * pGreen = pRed + ph->byte_per_line;
				BYTE * pBlue = pGreen + ph->byte_per_line;
				for(int x=0; x<nWidth; ++x, pOut += ph->color_planes)
				{
					pOut[0] = *pBlue++;
					pOut[1] = *pGreen++;
					pOut[2] = *pRed++;
				}

				pCur += ph->byte_per_line * ph->color_planes;
			}
		}
		else
		{//图象颠倒
			for(int y=0; y<nHeight; ++y)
			{
				BYTE * pOut = GetLine(m_nHeight - y - 1);
				BYTE * pRed = pCur;
				BYTE * pGreen = pRed + ph->byte_per_line;
				BYTE * pBlue = pGreen + ph->byte_per_line;
				for(int x=0; x<nWidth; ++x, pOut += ph->color_planes)
				{
					pOut[0] = *pBlue++;
					pOut[1] = *pGreen++;
					pOut[2] = *pRed++;
				}

				pCur += ph->byte_per_line * ph->color_planes;
			}
		}
		
		delete [] pImage;
	}

	//调色板
	if(nBitCount <= 8)
	{
		if(ph->palette_type <= 1) //彩色或者单色
		{
			if(ph->version == 3)	//使用系统自己的调色板
			{
				PALETTEENTRY pe[256];
				HDC hdc = ::GetDC(NULL);
				GetSystemPaletteEntries(hdc,0, 1<<nBitCount,pe);
				::ReleaseDC(NULL,hdc);
				for(int i=0; i<(1<<nBitCount); ++i)
				{
					m_pPal[i].rgbBlue = pe[i].peBlue;
					m_pPal[i].rgbGreen = pe[i].peGreen;
					m_pPal[i].rgbRed = pe[i].peRed;
					m_pPal[i].rgbReserved = pe[i].peFlags;
				}
			}
			else	//自带调色板
			{
				BYTE * pCurr = (nBitCount <= 4) ? 
							ph->palette : (pFileBuffer + nFileSize - 768);
				for(int i=0; i<(1<<nBitCount); ++i)
				{
					m_pPal[i].rgbRed = *pCurr++;
					m_pPal[i].rgbGreen = *pCurr++;
					m_pPal[i].rgbBlue = *pCurr++;
				}
			}
		}
		else	//灰度图
		{
			int nPerAdd = 256/(1<<nBitCount);
			for(int i=0; i<(1<<nBitCount); ++i)
			{
				m_pPal[i].rgbBlue = 
				m_pPal[i].rgbGreen = 
				m_pPal[i].rgbRed = 
					i * nPerAdd;
				m_pPal[i].rgbReserved = 0;
			}
		}
	}

	return TRUE;
}

//******************* 保存为PCX (由CDib对象) ***********************
BOOL LanImage::SavePcx(LPCTSTR lpstrFileName, CDib* pDib)
{
	if (pDib == NULL)
		return FALSE;

	HDIB hDib = CopyHandle(pDib->GetHandle());
	if (hDib == NULL)
		return FALSE;

	CDib* pDibTmp = new CDib();
	pDibTmp->Attach(hDib);

	UINT uWidth  = pDibTmp->GetWidth();
	UINT uHeight = pDibTmp->GetHeight();

	// 当打开的图像BitCount不为8时,转为8位格式
	if (pDibTmp->GetBitCount() != 8)
		pDibTmp->ConvertFormat(8);

	// make PCX header
	PCXHEAD header;
	memset((LPBYTE)&header, 0, sizeof(PCXHEAD));
	header.manufacturer = 0x0A;
	header.version = 5;
	header.encoding = 1;
	header.bit_per_pixel = 8;
	//header.bit_per_pixel = 24;
	header.xmin = 0;
	header.ymin = 0;
	header.xmax = uWidth-1;
	header.ymax = uHeight-1;
	//header.Xresolution;
	//header.Yresolution;
	header.palette[0] = (BYTE)0x00;  // for correct process for mono
	header.palette[1] = (BYTE)0x00;
	header.palette[2] = (BYTE)0x00;
	header.palette[3] = (BYTE)0xff;
	header.palette[4] = (BYTE)0xff;
	header.palette[5] = (BYTE)0xff;
	//header.palette[48];
	header.reserved = 0;
	header.color_planes = 1;
	header.byte_per_line = uWidth;
	header.palette_type = 1;
	//filler[58];

	// construct PCX palette from DIB color table
	PCXPALETTE palette[256];
	PALETTEENTRY PaletteColors[256];
	pDibTmp->GetPalette()->GetPaletteEntries(0, 256, PaletteColors);
	for (int i=0;i<256;i++) 
	{
		palette[i].rgbRed   = PaletteColors[i].peRed;
		palette[i].rgbGreen = PaletteColors[i].peGreen;
		palette[i].rgbBlue  = PaletteColors[i].peBlue;
	}

	// get bits ptr
	HDIB hDIB = CopyHandle(pDibTmp->GetHandle());
	delete pDibTmp;
	LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB);
	BYTE* lpBuffer = (BYTE *)FindDIBBits(lpDIB);
	WORD wWidthBytes = (WORD)BytesPerLine(lpDIB);

	/*** Open the PCX file ***/
	FILE *outFile;
	if ((outFile=fopen(lpstrFileName,"wb")) == NULL)
	{
		GlobalUnlock(hDIB);
		GlobalFree(hDIB);
		return FALSE;
	}

	/*** Write the header ***/
	fwrite((char *)&header, sizeof(PCXHEAD), 1, outFile);

	/*** Write image data ***/
	for ( i=(int)uHeight-1; i>=0; --i)
	{
		if (! WritePCXLine(header.byte_per_line, lpBuffer+i*wWidthBytes, outFile))
		{
			fclose(outFile);
			GlobalUnlock(hDIB);
			GlobalFree(hDIB);
			return FALSE;
		}
	}

	/*** Write the palette data ***/
	fputc(0x0c, outFile);
	fwrite((char *)palette, 1, sizeof(palette), outFile);

	// clear & close
	fclose(outFile);
	GlobalUnlock(hDIB);
	GlobalFree(hDIB);

	return TRUE;
}